package dnaSequencer;

import java.util.ArrayList;

public class DNAPiece {
	private String dna = null;
	private ArrayList<String> oligonukleotydy = null;
	private int singlePieceLength;

	public static final int FRONT = 1;
	public static final int BACK = 2;

	public DNAPiece(int singlePieceLength) {
		dna = new String();
		oligonukleotydy = new ArrayList<String>();
		this.singlePieceLength = singlePieceLength;
	}

	public DNAPiece(int singlePieceLength, String oligonukleotyd) {
		dna = new String(oligonukleotyd);
		oligonukleotydy = new ArrayList<String>();
		oligonukleotydy.add(oligonukleotyd);
		this.singlePieceLength = singlePieceLength;
	}
	
	public DNAPiece(DNAPiece template){
		this.dna = new String(template.getDNA());
		this.oligonukleotydy = new ArrayList<String>();
		for (String a : template.getOligonukleotydy())
			this.oligonukleotydy.add(new String(a));
		this.singlePieceLength = template.getSinglePieceLength();
	}
	
	public int getSinglePieceLength(){
		return singlePieceLength;
	}

	public void add(String piece, int end) {
		/* Dodajemy nukleotydy z przodu */
		if (end == FRONT) {
			oligonukleotydy.add(0, piece);
			if (dna.equals(""))
				dna = piece;
			else {
				int zakladka = singlePieceLength - 1;
				while (zakladka < singlePieceLength) {
					boolean done = true;
					for (int i = 0; i < zakladka; i++) {
						if (piece.charAt(piece.length() - zakladka + i) != dna
								.charAt(i)) {
							done = false;
							break;
						}
					}
					if (done)
						break;
					else
						zakladka--;
				}

				dna = piece.substring(0, piece.length() - zakladka) + dna;

			}

		} /* Dodajemy nukleotydy z tyłu */
		else if (end == BACK) {
			oligonukleotydy.add(piece);
			if (dna.equals(""))
				dna = piece;
			else {
				int zakladka = singlePieceLength - 1;
				while (zakladka < singlePieceLength) {
					boolean done = true;
					for (int i = 0; i < zakladka; i++) {
						if (piece.charAt(i) != dna.charAt(dna.length()
								- zakladka + i)) {
							done = false;
							break;
						}
					}
					if (done)
						break;
					else
						zakladka--;
				}

				dna += piece.substring(zakladka);

			}

		}
	}

	public void addInRebuild(String piece) {

		if (dna.equals(""))
			dna = piece;
		else {
			int zakladka = singlePieceLength - 1;
			while (zakladka < singlePieceLength) {
				boolean done = true;
				for (int i = 0; i < zakladka; i++) {
					if (piece.charAt(i) != dna.charAt(dna.length() - zakladka
							+ i)) {
						done = false;
						break;
					}
				}
				if (done)
					break;
				else
					zakladka--;
			}

			dna += piece.substring(zakladka);

		}

	}

	public void add(DNAPiece dp, int end) {
		if (end == FRONT) {
			ArrayList<String> oligTmp = dp.getOligonukleotydy();
			String piece = dp.getDNA();

			int i = oligTmp.size() - 1;
			while (i >= 0) {
				oligonukleotydy.add(0, oligTmp.get(i));
				i--;
			}

			if (dna.equals(""))
				dna = dp.getDNA();
			else {
				int zakladka = singlePieceLength - 1;
				while (zakladka < singlePieceLength) {
					boolean done = true;
					for (i = 0; i < zakladka; i++) {
						if (piece.charAt(piece.length() - zakladka + i) != dna
								.charAt(i)) {
							done = false;
							break;
						}
					}
					if (done)
						break;
					else
						zakladka--;
				}

				dna = piece.substring(0, piece.length() - zakladka) + dna;

			}
		} else if (end == BACK) {
			ArrayList<String> oligTmp = dp.getOligonukleotydy();
			String piece = dp.getDNA();

			for (String a : oligTmp) {
				oligonukleotydy.add(a);
			}
			if (dna.equals(""))
				dna = piece;
			else {
				int zakladka = singlePieceLength - 1;
				while (zakladka < singlePieceLength) {
					boolean done = true;
					for (int i = 0; i < zakladka; i++) {
						if (piece.charAt(i) != dna.charAt(dna.length()
								- zakladka + i)) {
							done = false;
							break;
						}
					}
					if (done)
						break;
					else
						zakladka--;
				}
				dna += piece.substring(zakladka);
			}
		}
	}

	public String getDNA() {
		return dna;
	}

	public int getDNALength() {
		return dna.length();
	}

	public int getUseWordsCount() {
		return oligonukleotydy.size();
	}

	public ArrayList<String> getOligonukleotydy() {
		return oligonukleotydy;
	}

	public String getWord(int i) {
		return oligonukleotydy.get(i);
	}

	public void show() {
		System.out.println(dna);
		for (String a : oligonukleotydy)
			System.out.println(a);
	}

	public void insertFullOK(DNAPiece piece) {
		int i = 0;
		while (i < oligonukleotydy.size() - 2) {
			int zak1 = getZakladkaLength(oligonukleotydy.get(i), piece.getDNA());
			int zak2 = getZakladkaLength(piece.getDNA(), oligonukleotydy
					.get(i + 1));
			if (zak1 + zak2 >= singlePieceLength) {
				ArrayList<String> doDodania = piece.getOligonukleotydy();
				for (int j = doDodania.size() - 1; j >= 0; j--)
					oligonukleotydy.add(i + 1, doDodania.get(j));
				break;
			}
			i++;

		}
	}

	public void insertBestFit(DNAPiece piece) {
		int bestZakladka = getZakladkaLength(piece.getDNA(), oligonukleotydy
				.get(0));
		int bestIndex = -1;

		int i = 0;

		while (i < oligonukleotydy.size() - 2) {
			int zak1 = getZakladkaLength(oligonukleotydy.get(i), piece.getDNA());
			int zak2 = getZakladkaLength(piece.getDNA(), oligonukleotydy
					.get(i + 1));
			if (zak1 + zak2 > bestZakladka) {
				bestIndex = i;
				bestZakladka = zak1 + zak2;
			}
			i++;
		}

		if (getZakladkaLength(oligonukleotydy.get(oligonukleotydy.size() - 1),
				piece.getDNA()) > bestZakladka) {
			bestIndex = oligonukleotydy.size();
			bestZakladka = getZakladkaLength(oligonukleotydy
					.get(oligonukleotydy.size() - 1), piece.getDNA());
		}

		ArrayList<String> doDodania = piece.getOligonukleotydy();

		if (bestIndex == oligonukleotydy.size()) {
			for (String a : doDodania) {
				oligonukleotydy.add(a);
			}

		} else {

			for (int j = doDodania.size() - 1; j >= 0; j--) {

				oligonukleotydy.add(bestIndex + 1, doDodania.get(j));
			}
		}

		rebuildDNA();

	}

	public int insertBestFit(ArrayList<DNAPiece> colliding) {
		int bestZakladka = getZakladkaLength(colliding.get(0).getDNA(),
				oligonukleotydy.get(0));
		int bestIndex = -1;
		int bestPiece = 0;

		for (int kawalek = 0; kawalek < colliding.size(); kawalek++) {

			DNAPiece piece = colliding.get(kawalek);
			
			if (getZakladkaLength(piece.getDNA(),oligonukleotydy.get(0)) > bestZakladka){
				bestIndex = -1;
				bestPiece = kawalek;
				bestZakladka = getZakladkaLength(piece.getDNA(),oligonukleotydy.get(0));
			}
			
			
			int i = 0;

			while (i < oligonukleotydy.size() - 2) {
				int zak1 = getZakladkaLength(oligonukleotydy.get(i), piece
						.getDNA());
				int zak2 = getZakladkaLength(piece.getDNA(), oligonukleotydy
						.get(i + 1));
				if (zak1 + zak2 > bestZakladka) {
					bestIndex = i;
					bestZakladka = zak1 + zak2;
					bestPiece = kawalek;					
				}
				i++;
			}

			if (getZakladkaLength(oligonukleotydy
					.get(oligonukleotydy.size() - 1), piece.getDNA()) > bestZakladka) {
				bestIndex = oligonukleotydy.size();
				bestZakladka = getZakladkaLength(oligonukleotydy
						.get(oligonukleotydy.size() - 1), piece.getDNA());
				bestPiece = kawalek;
			}
		}

		ArrayList<String> doDodania = colliding.get(bestPiece).getOligonukleotydy();

		if (bestIndex == oligonukleotydy.size()) {
			for (String a : doDodania) {
				oligonukleotydy.add(a);
			}

		} else {

			for (int j = doDodania.size() - 1; j >= 0; j--) {

				oligonukleotydy.add(bestIndex + 1, doDodania.get(j));
			}
		}

		rebuildDNA();
		return bestPiece;

	}

	public int getZakladkaLength(int side) {
		if (oligonukleotydy.size() < 2)
			return 0;
		String first = null;
		String second = null;
		if (side == BACK) {
			first = oligonukleotydy.get(oligonukleotydy.size() - 2);
			second = oligonukleotydy.get(oligonukleotydy.size() - 1);
		} else if (side == FRONT) {
			first = oligonukleotydy.get(0);
			second = oligonukleotydy.get(1);
		}

		int i = 1;
		while (i <= singlePieceLength) {
			if (first.substring(i).equalsIgnoreCase(
					second.substring(0, singlePieceLength - i)))
				return singlePieceLength - i;
			i++;
		}
		return 0;

	}

	public int getZakladkaLength(DNAPiece dna, int side) {
		String first = null;
		String second = null;

		if (side == BACK) {
			first = oligonukleotydy.get(oligonukleotydy.size() - 1);
			second = dna.getDNA();
		} else if (side == FRONT) {
			first = dna.getDNA();
			second = oligonukleotydy.get(0);
		}

		int i = 1;
		while (i <= singlePieceLength) {
			if (first.substring(first.length() - singlePieceLength + i)
					.equalsIgnoreCase(
							second.substring(0, singlePieceLength - i)))
				return singlePieceLength - i;
			i++;
		}
		return 0;

	}

	public int getZakladkaLength(String first, String second) {

		int i = 1;
		while (i <= singlePieceLength) {
			if (first.substring(first.length() - singlePieceLength + i)
					.equalsIgnoreCase(
							second.substring(0, singlePieceLength - i)))
				return singlePieceLength - i;
			i++;
		}
		return 0;

	}

	public void removeOne(int side) {
		if (side == BACK) {
			dna = dna.substring(0, dna.length() - singlePieceLength
					+ getZakladkaLength(BACK));
			oligonukleotydy.remove(oligonukleotydy.size() - 1);
		} else if (side == FRONT) {
			dna = dna.substring(singlePieceLength - getZakladkaLength(FRONT));
			oligonukleotydy.remove(0);
		}
	}

	private void rebuildDNA() {
		dna = new String();
		for (String piece : oligonukleotydy) {
			addInRebuild(piece);
		}
	}

}
